/**HEADER********************************************************************
* 
* Copyright (c) 2008 Freescale Semiconductor;
* All Rights Reserved
*
* Copyright (c) 2004-2010 Embedded Access Inc.;
* All Rights Reserved
*
* Copyright (c) 1989-2008 ARC International;
* All Rights Reserved
*
*************************************************************************** 
*
* THIS SOFTWARE IS PROVIDED BY FREESCALE "AS IS" AND ANY EXPRESSED OR 
* IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES 
* OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.  
* IN NO EVENT SHALL FREESCALE OR ITS CONTRIBUTORS BE LIABLE FOR ANY DIRECT, 
* INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES 
* (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR 
* SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) 
* HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, 
* STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING 
* IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF 
* THE POSSIBILITY OF SUCH DAMAGE.
*
**************************************************************************
*
* $FileName: mpc83xx_etsec_init.c$
* $Version : 3.8.1.0$
* $Date    : May-12-2011$
*
* Comments:
*
*   This file initializes the 83xx ethernet interface.
*
*END************************************************************************/

#include <mqx.h>
#include <bsp.h>
#include <bsp_prv.h>
#include <ethernet.h>
#include <enet.h>
#include <enetprv.h>
#include <mdio.h>
#include <mpc83xx_etsec_prv.h>


const ENET_MAC_IF_STRUCT MPC83xx_MAC_IF = {
    MPC83xx_etsec_initialize,
    MPC83xx_etsec_shutdown,
    MPC83xx_etsec_send_MAC,
    MPC83xx_etsec_read_mdio,
    MPC83xx_etsec_write_mdio
    
#if BSPCFG_ENABLE_ENET_MULTICAST
    ,
    MPC83xx_etsec_join_MAC,
    MPC83xx_etsec_rejoin_MAC
#endif
};


/*FUNCTION*-------------------------------------------------------------
*
*  Function Name  : MPC83xx_etsec_write
*  Returned Value : none
*  Comments       :
*
*END*-----------------------------------------------------------------*/


void MPC83xx_etsec_write(vuint_32_ptr addr, uint_32 val, char * reg)
{
   *addr = val;
   _PSP_SYNC();
}   

/*FUNCTION*-------------------------------------------------------------
*
*  Function Name  : MPC83xx_etsec_check_mode
*  Returned Value : ENET_OK or error
*  Comments       :
*        Compares TSEC mode defined in Reset Configuration Word High
*        Register.
*
*END*-----------------------------------------------------------------*/

static uint_32 MPC83xx_etsec_check_mode(uint_32 device, uint_32 mode)
{ 
   MPC83xx_RSTMOD_STRUCT_PTR    rstmod_ptr;
   uint_32                      tsecmode;
   uint_32                      immr;
   uint_32                      error;
   
   immr = (uint_32)BSP_IMMR_BASE;
   
   rstmod_ptr = (MPC83xx_RSTMOD_STRUCT_PTR)(immr + MPC83xx_RESET_MODULE_BASE);
   
   if(device == 0) {
      /* TSEC1 */
      tsecmode = rstmod_ptr->RCWHR & MPC83xx_RSTMOD_RCWHR_TSEC1M_MASK;
      
      if((mode == MPC83xx_ETH_MODE_MII) && 
         (tsecmode == MPC83xx_RSTMOD_RCWHR_TSEC1M_MII)) {
      	error = ENET_OK;
      }
      else if((mode == MPC83xx_ETH_MODE_GMII) && 
         (tsecmode == MPC83xx_RSTMOD_RCWHR_TSEC1M_GMII)) {
      	error = ENET_OK;
      }
      else if((mode == MPC83xx_ETH_MODE_RGMII) && 
         (tsecmode == MPC83xx_RSTMOD_RCWHR_TSEC1M_RGMII)) {
      	error = ENET_OK;
      }
      else if((mode == MPC83xx_ETH_MODE_TBI) && 
         (tsecmode == MPC83xx_RSTMOD_RCWHR_TSEC1M_TBI)) {
      	error = ENET_OK;
      }
      else if((mode == MPC83xx_ETH_MODE_RTBI) && 
         (tsecmode == MPC83xx_RSTMOD_RCWHR_TSEC1M_RTBI)) {
      	error = ENET_OK;
      }
      else {
      	error = ENETERR_INIT_FAILED;
      } 
   }
   else {
      /* TSEC2 */
      tsecmode = rstmod_ptr->RCWHR & MPC83xx_RSTMOD_RCWHR_TSEC2M_MASK;
      
      if((mode == MPC83xx_ETH_MODE_MII) && 
         (tsecmode == MPC83xx_RSTMOD_RCWHR_TSEC2M_GMII)) {
      	error = ENET_OK;
      }
      else if((mode == MPC83xx_ETH_MODE_GMII) && 
         (tsecmode == MPC83xx_RSTMOD_RCWHR_TSEC2M_GMII)) {
      	error = ENET_OK;
      }
      else if((mode == MPC83xx_ETH_MODE_RGMII) && 
         (tsecmode == MPC83xx_RSTMOD_RCWHR_TSEC2M_RGMII)) {
      	error = ENET_OK;
      }
      else if((mode == MPC83xx_ETH_MODE_TBI) && 
         (tsecmode == MPC83xx_RSTMOD_RCWHR_TSEC2M_TBI)) {
      	error = ENET_OK;
      }
      else if((mode == MPC83xx_ETH_MODE_RTBI) && 
         (tsecmode == MPC83xx_RSTMOD_RCWHR_TSEC2M_RTBI)) {
      	error = ENET_OK;
      }
      else {
      	error = ENETERR_INIT_FAILED;
      } 
   } 
   
   return(error);

} 



/*FUNCTION*-------------------------------------------------------------
*
*  Function Name  : MPC83xx_etsec_init_ring
*  Returned Value : void
*  Comments       :
*        Initializes the buffer descriptor rings.
*
*END*-----------------------------------------------------------------*/

void MPC83xx_etsec_init_ring
   (
      /* [IN] the Ethernet state structure */
      ENET_CONTEXT_STRUCT_PTR  enet_ptr
   )
{ 
   MPC83XX_TSEC_CONTEXT_STRUCT_PTR tsec_context_ptr;
   VMPC83xx_TSEC_BD_STRUCT_PTR     bd_ptr;
   uint_32                         i;
   uint_32                         rx_size = sizeof(VMPC83xx_TSEC_BD_STRUCT)* BSPCFG_RX_RING_LEN;
   uint_32                         tx_size = sizeof(VMPC83xx_TSEC_BD_STRUCT)* BSPCFG_TX_RING_LEN;

   tsec_context_ptr = (MPC83XX_TSEC_CONTEXT_STRUCT_PTR)enet_ptr->MAC_CONTEXT_PTR;

   _mem_zero((void *)tsec_context_ptr->TSEC_RX_RING_PTR, rx_size);
   _mem_zero((void *)tsec_context_ptr->TSEC_TX_RING_PTR, tx_size);
   
   _DCACHE_FLUSH_MLINES((void *)tsec_context_ptr->TSEC_RX_RING_PTR, rx_size);
   _DCACHE_FLUSH_MLINES((void *)tsec_context_ptr->TSEC_TX_RING_PTR, tx_size);

   /* First the receive ring ... */
   bd_ptr = tsec_context_ptr->TSEC_RX_RING_PTR;
   i = BSPCFG_RX_RING_LEN + 1;
   while ( --i ) {
      bd_ptr->CONTROL = MPC83xx_TSEC_BD_RX_INTERRUPT;
      _PSP_EIEIO();
      bd_ptr->LENGTH  = 0;
      _PSP_EIEIO();
      bd_ptr->BUFFER  = 0;
      _PSP_EIEIO();
      bd_ptr++;
   } /* Endwhile */

   /* Set wrap bit in last BD */
   tsec_context_ptr->TSEC_RX_RING_PTR[BSPCFG_RX_RING_LEN - 1].CONTROL |= MPC83xx_TSEC_BD_RX_WRAP;
   _PSP_EIEIO();

   _DCACHE_FLUSH_MLINES((void *)tsec_context_ptr->TSEC_RX_RING_PTR, rx_size);

   /* ... then the transmit ring */
   bd_ptr = tsec_context_ptr->TSEC_TX_RING_PTR;
   i = BSPCFG_TX_RING_LEN + 1;
   while ( --i ) {
      bd_ptr->CONTROL = MPC83xx_TSEC_BD_TX_INTERRUPT | MPC83xx_TSEC_BD_TX_PAD | MPC83xx_TSEC_BD_TX_CRC;
      _PSP_EIEIO();
      bd_ptr->LENGTH  = 0x0000;
      _PSP_EIEIO();
      bd_ptr->BUFFER  = 0;
      _PSP_EIEIO();
      bd_ptr++;
   } /* Endwhile */

   /* Set wrap bit in last BD */
   tsec_context_ptr->TSEC_TX_RING_PTR[BSPCFG_TX_RING_LEN - 1].CONTROL |= MPC83xx_TSEC_BD_TX_WRAP;
   _PSP_EIEIO();
   
   _DCACHE_FLUSH_MLINES((void *)tsec_context_ptr->TSEC_TX_RING_PTR, tx_size);

   /* Initialize the state structure */
   tsec_context_ptr->RxPCBHead      = NULL;
   tsec_context_ptr->RxPCBTail      = NULL;
   tsec_context_ptr->ActiveRxBDs    = 0;
   tsec_context_ptr->NextRxBD       = 0;
   tsec_context_ptr->LastRxBD       = 0;
   tsec_context_ptr->AvailableTxBDs = BSPCFG_TX_RING_LEN;
   tsec_context_ptr->NextTxBD       = 0;
   tsec_context_ptr->LastTxBD       = 0;
   tsec_context_ptr->TxErrors       = 0;
} 


/*FUNCTION*-------------------------------------------------------------
*
*  Function Name  : MPC83xx_etsec_get_interface
*  Returned Value : ENET_OK or error code
*  Comments       :
*        Returns interfave type (for debugging)
*
*END*-----------------------------------------------------------------*/

static char *  MPC83xx_etsec_get_interface(uint_32 ecntrl)
{
	if (ecntrl & MPC83xx_TSEC_ECTRL_SGMIIM)
		return "SGMII";

	if (ecntrl & MPC83xx_TSEC_ECTRL_TBIM) {
		if (ecntrl & MPC83xx_TSEC_ECTRL_RPM)
			return "RTBI";
		else
			return "TBI";
	}

	if (ecntrl & MPC83xx_TSEC_ECTRL_RPM) {
		if (ecntrl & MPC83xx_TSEC_ECTRL_RMM)
			return "RMII";
		else {
			return "RGMII";
		}
	}

	return "GMII";
}


/*FUNCTION*-------------------------------------------------------------
*
*  Function Name  : MPC83xx_etsec_initialize
*  Returned Value : ENET_OK or error code
*  Comments       :
*        Initializes the chip (extended version).
*
*END*-----------------------------------------------------------------*/

#define IF_ERROR_EXIT(c,x) {if (c) { error = x; goto EXIT; }}


uint_32 MPC83xx_etsec_initialize ( ENET_CONTEXT_STRUCT_PTR enet_ptr )
{ 
   MPC83XX_TSEC_CONTEXT_STRUCT_PTR  tsec_context_ptr=NULL;
   MPC83xx_ETSEC_STRUCT_PTR         tsec_ptr;
   PCB_PTR                          pcb_ptr;
   uint_32                          error = ENET_OK;
   uchar_ptr                        pcb_base, buf_ptr;
   uint_32                          tsecmode;
   uint_32                          i;
   uint_32                          speed;
   uchar                            device = enet_ptr->PARAM_PTR->ENET_IF->MAC_NUMBER;
   uint_32                          tmp;
   uint_32                          rx_size = sizeof(VMPC83xx_TSEC_BD_STRUCT)* BSPCFG_RX_RING_LEN;
   uint_32                          tx_size = sizeof(VMPC83xx_TSEC_BD_STRUCT)* BSPCFG_TX_RING_LEN;
   uint_32                          ectrl, maccfg1,maccfg2;
   boolean                          bOK;
   
   /*
   ** This function can be called from any context, and it needs mutual
   ** exclusion with itself.
   */
   etsec_lock();
   IF_ERROR_EXIT(enet_ptr == NULL,ENETERR_INIT_DEVICE);

   // allocate the device context   
   tsec_context_ptr = _mem_alloc_system_zero(sizeof(MPC83XX_TSEC_CONTEXT_STRUCT));
   IF_ERROR_EXIT(tsec_context_ptr == NULL,ENETERR_ALLOC_MAC_CONTEXT);
   _mem_set_type((pointer)tsec_context_ptr, MEM_TYPE_IO_ENET_MAC_CONTEXT_STRUCT);
   enet_ptr->MAC_CONTEXT_PTR = (pointer) tsec_context_ptr;  

   // Allocate the PCBs 
   pcb_base = (void *)_mem_alloc_system_uncached(BSPCFG_RX_RING_LEN * (sizeof(PCB) + sizeof(PCB_FRAGMENT) +
      ENET_FRAMESIZE_ALIGN(ENET_FRAMESIZE_MAXDATA) + ENET_FRAMESIZE_ALIGN(1)) + ENET_FRAMESIZE_ALIGN(1));
   IF_ERROR_EXIT(pcb_base == NULL,ENETERR_ALLOC_PCB);
   _mem_zero(pcb_base, _mem_get_size(pcb_base));
   
   tsec_context_ptr->RX_PCB_BASE = (MPC83XX_TSEC_RX_PCB_PTR)pcb_base;
          
   // Allocate the Rx Ring 
   tsec_context_ptr->TSEC_RX_RING_PTR = (VMPC83xx_TSEC_BD_STRUCT_PTR)_mem_alloc_system_uncached(rx_size);
   IF_ERROR_EXIT(tsec_context_ptr->TSEC_RX_RING_PTR == NULL,ENETERR_ALLOC_BD);
   _mem_zero((pointer)tsec_context_ptr->TSEC_RX_RING_PTR, rx_size);
 
   // Allocate the Tx Ring 
   tsec_context_ptr->TSEC_TX_RING_PTR = (VMPC83xx_TSEC_BD_STRUCT_PTR)_mem_alloc_system_uncached(tx_size);
   IF_ERROR_EXIT(tsec_context_ptr->TSEC_TX_RING_PTR == NULL,ENETERR_ALLOC_BD);
   _mem_zero((pointer)tsec_context_ptr->TSEC_TX_RING_PTR, tx_size);

   // Install ENET ISRs
   MPC83xx_etsec_install_isrs(enet_ptr);
   
   // Initialize device address
   tsec_ptr =  MPC83xx_etsec_get_base_address(device);
   tsec_context_ptr->TSEC_ADDRESS = tsec_ptr;

   // Initialize TSEC clocks
   MPC83xx_etsec_clock_config(device);

   // Configure TSEC GPIO Pins 
   MPC83xx_etsec_pin_config( device);
   
   /* TBI (Ten Bit Interface) Physical Address */
   TSEC_WRITE(tsec_ptr->TBIPA, MPC837x_TSEC_TBIPA_ADDR);

   // Discover PHY address if PHY_DISCOVER option is set
   if (enet_ptr->PARAM_PTR->OPTIONS & ENET_OPTION_PHY_DISCOVER) {
      bOK = (*enet_ptr->PARAM_PTR->ENET_IF->PHY_IF->DISCOVER)(enet_ptr);
      IF_ERROR_EXIT(!bOK, ENETERR_INIT_FAILED);
   } else {
      // Set Phy address from initialization parameter
      enet_ptr->PHY_ADDRESS = enet_ptr->PARAM_PTR->ENET_IF->PHY_ADDRESS;
   }
   
   /* Reset TSEC */
   TSEC_WRITE_WITH_DELAY(tsec_ptr->MACCFG1, MPC83xx_TSEC_MACCFG1_SOFT_RESET);

   /* Clear Soft Reset */
   TSEC_WRITE_WITH_DELAY(tsec_ptr->MACCFG1, 0);

   TSEC_WRITE(tsec_ptr->IEVENT, ~0);
   TSEC_WRITE(tsec_ptr->IMASK, 0);

   /* Clear the hash table registers.*/
   for ( i = 0; i < 8; i++) {
      TSEC_WRITE(tsec_ptr->IADDR[i], 0);
    } 
   for ( i = 0; i < 8; i++) {
      TSEC_WRITE(tsec_ptr->GADDR[i], 0);
   } 
   TSEC_WRITE(tsec_ptr->CAM1, ~0);
   TSEC_WRITE(tsec_ptr->CAM2, ~0);
   for ( i = 0; i < 15; i++) {
      TSEC_WRITE(tsec_ptr->MACADDR[i].P1,0);
      TSEC_WRITE(tsec_ptr->MACADDR[i].P2,0);
   }

   /* Initialize the descriptor rings */
   MPC83xx_etsec_init_ring(enet_ptr);

   /* Enqueue the PCBs onto the receive ring */
   pcb_ptr = (PCB_PTR)pcb_base;
   buf_ptr = pcb_base + BSPCFG_RX_RING_LEN * (sizeof(PCB) + sizeof(PCB_FRAGMENT));
   buf_ptr = (uchar_ptr)ENET_FRAMESIZE_ALIGN((uint_32)buf_ptr);
   i = BSPCFG_RX_RING_LEN + 1;
   while ( --i ) {
      pcb_ptr->FREE    = MPC83xx_etsec_rx_add;
      pcb_ptr->PRIVATE = enet_ptr;
         /* pcb_ptr->FRAG[0].LENGTH filled in by RxCatchup */
      pcb_ptr->FRAG[0].FRAGMENT = buf_ptr;
      pcb_ptr->FRAG[1].LENGTH   = 0;
      pcb_ptr->FRAG[1].FRAGMENT = NULL;
      MPC83xx_etsec_rx_add(pcb_ptr);
      pcb_ptr = (PCB_PTR)((uchar_ptr)pcb_ptr + sizeof(PCB) + sizeof(PCB_FRAGMENT));
      buf_ptr += ENET_FRAMESIZE_ALIGN(ENET_FRAMESIZE_MAXDATA) + ENET_FRAMESIZE_ALIGN(1);
   } 

   TSEC_WRITE(tsec_ptr->MACCFG1, MPC83xx_TSEC_MACCFG1_RXFLOW | MPC83xx_TSEC_MACCFG1_TXFLOW);
   
   /* Maximum Receive Buffer Length, multiple of 64 */
   TSEC_WRITE(tsec_ptr->MRBLR, 256 * 6);
   TSEC_WRITE(tsec_ptr->MAXFRM, 256 * 6);

   // This register is not available in the 8308 
   TSEC_WRITE(tsec_ptr->MINFLR, 0x40);

   /* Reset RCTRL, disable TOE functionality */
   TSEC_WRITE(tsec_ptr->RCTRL, 0 );
   
   /* Program this station's Ethernet physical address */
   TSEC_WRITE(tsec_ptr->MACSTNADDR.P2, (enet_ptr->ADDRESS[1] << 24) | (enet_ptr->ADDRESS[0] << 16));
   TSEC_WRITE(tsec_ptr->MACSTNADDR.P1, (enet_ptr->ADDRESS[5] << 24) | (enet_ptr->ADDRESS[4] << 16) |(enet_ptr->ADDRESS[3] << 8) | enet_ptr->ADDRESS[2]);
   
   /* Clear DMA Control register */
   tmp = MPC83xx_TSEC_DMACTRL_TDSEN | MPC83xx_TSEC_DMACTRL_TBDSEN| MPC83xx_TSEC_DMACTRL_WWR;
   TSEC_WRITE_WITH_DELAY(tsec_ptr->DMACTRL, tmp | MPC83xx_TSEC_DMACTRL_GRS | MPC83xx_TSEC_DMACTRL_GTS);
   TSEC_WRITE(tsec_ptr->DMACTRL, tmp );

    /* Setup Managemet Clock(MDC) */                     
   TSEC_WRITE_WITH_DELAY(tsec_ptr->MIIMCFG, MPC83xx_TSEC_MIIMCFG_MGMT_RESET);
    
   /* Setup Managemet Clock(MDC) */                     
   TSEC_WRITE(tsec_ptr->MIIMCFG, MPC83xx_TSEC_MIIMCFG_MDC_DIV_8);
   
   TSEC_WRITE(tsec_ptr->IEVENT, 0xFFFFFFFF);
   TSEC_WRITE(tsec_ptr->IMASK, 0);

   TSEC_WRITE(tsec_ptr->TXIC, 0);
   TSEC_WRITE(tsec_ptr->RXIC, 0);
   TSEC_WRITE(tsec_ptr->ATTR, 0);
   TSEC_WRITE(tsec_ptr->ATTRELI, 0);
   
   // Perform Phy initialization
   bOK = (*enet_ptr->PARAM_PTR->ENET_IF->PHY_IF->INIT)(enet_ptr);
   IF_ERROR_EXIT(!bOK, ENETERR_INIT_FAILED);

   /* Get Autonegotiated Link Speed */
   speed = ENET_get_speed(enet_ptr);

   maccfg2 = MPC83xx_TSEC_MACCFG2_PREAMLEN7 | MPC83xx_TSEC_MACCFG2_PAD_CRC; 
   ectrl = tsec_ptr->ECTRL & (MPC83xx_TSEC_ECTRL_GMII|MPC83xx_TSEC_ECTRL_RPM);

   switch (speed) {
      case 1000:
         /* Configure I/F to 2 for 1000 Mbps (RGMII) */
   	   maccfg2 |= MPC83xx_TSEC_MACCFG2_IF_BYTE_MODE;
   	   ectrl |= MPC83xx_TSEC_ECTRL_STEN | MPC83xx_TSEC_ECTRL_GMII; // RGMII interface
         break;
         
      case 100:
         /*  Configure I/F to 1 for 10/100 Mbps (MII/RMII) */
   	   maccfg2 |= MPC83xx_TSEC_MACCFG2_IF_NIBBLE;
         /* Configure Ethernet Control for Statistics Enabled (STEN) and 100 Mbps (R100M) mode */
         ectrl |= MPC83xx_TSEC_ECTRL_STEN | MPC83xx_TSEC_ECTRL_R100M;  
         break;
      
      case 10:
         /*  Configure I/F to 1 for 10/100 Mbps (MII/RMII) */
   	   maccfg2 |= MPC83xx_TSEC_MACCFG2_IF_NIBBLE;
   	   ectrl |= MPC83xx_TSEC_ECTRL_STEN;
         break;
      
      default:
         break;

   }      

   /* Match Duplex found in Autonegotiation */
   if (enet_ptr->PARAM_PTR->ENET_IF->PHY_IF->DUPLEX) {
      if ((*enet_ptr->PARAM_PTR->ENET_IF->PHY_IF->DUPLEX)(enet_ptr)) {
         maccfg2 |= MPC83xx_TSEC_MACCFG2_FULL_DUPLEX;
      }   
  }
      
   TSEC_WRITE(tsec_ptr->MACCFG2, maccfg2);
   TSEC_WRITE(tsec_ptr->ECTRL, ectrl);

   TSEC_WRITE(tsec_ptr->TBASE[0].ADDR, (uint_32)tsec_context_ptr->TSEC_TX_RING_PTR);
   TSEC_WRITE(tsec_ptr->RBASE[0].ADDR, (uint_32)tsec_context_ptr->TSEC_RX_RING_PTR);
   
   // Enable interrupts at TSEC level
   TSEC_WRITE(tsec_ptr->IMASK,  MPC83xx_TSEC_IEVENT_TXF | MPC83xx_TSEC_IEVENT_RXF);

   // Enable interrupts at the IPIC level
   MPC83xx_etsec_enable_ints(enet_ptr);
   
   /* Enable RX and Tx */
   maccfg1 = tsec_ptr->MACCFG1;
   maccfg1 |= MPC83xx_TSEC_MACCFG1_RX_ENABLE | MPC83xx_TSEC_MACCFG1_TX_ENABLE;
   TSEC_WRITE(tsec_ptr->MACCFG1, maccfg1);

   TSEC_WRITE(tsec_ptr->RSTAT, 0x00800000);
   TSEC_WRITE(tsec_ptr->TSTAT, 0x80000000);

   
   // control transfers to this point on any error, with error set to error code.
EXIT:
   if (ENET_OK!=error) {
      MPC83xx_etsec_uninstall_all_isrs(enet_ptr);
      MPC83xx_etsec_free_context(tsec_context_ptr);
   }
   etsec_unlock();

   return error;
} 

/* EOF */
